// JORGE FERNANDO GOMEZ
// 1259371
// 189631
// LEC A1
// MARTIN MÜLLER
// D02
// YANG LIU


#include "util.h"
#include "process.h"


/* classifyLines() takes a Line * Lines, and tags each line stored according
 * to its first keyword.  Keywords must not have leading whitespace, or
 * classifyLines() will fail.  Returns 0 if successful, or 1 if a line
 * contains bad format. */
int classifyLines ( Line * Lines ) {

    int currentLine = 0;
    while( currentLine < inputFileLength ) {

        /* Tag each line appropriately.  Echoes comments to stdout.
         * If "Figure" is the keyword found, increase figure counter. */

        /* **NOTE**
         *
         * All comments are echoed out except comments preceeding the
         * child end command, following the "Specification" example from
         * the course website. */

        if ( strncmp( Lines[currentLine].lineString, "#", strlen("#")) == 0 ) {
            Lines[currentLine].commandType = COMMENT;
            if ( (inputFileLength - currentLine) != 2 ) {
                printf("%s\n", Lines[currentLine].lineString);
            }
        }
        else if ( strncmp( Lines[currentLine].lineString, "Figure ",
                    strlen("Figure ")) == 0 ) {
            Lines[currentLine].commandType = FIGURE;
            figureCount++;
        }
        else if ( strncmp( Lines[currentLine].lineString, "End",
                    strlen("End")) == 0 ) {
            Lines[currentLine].commandType = END;
        }
        else if ( strncmp( Lines[currentLine].lineString, "draw ",
                    strlen("draw ")) == 0 ) {
            Lines[currentLine].commandType = DRAW;
        }
        else if ( strncmp( Lines[currentLine].lineString, "drawFigure ",
                    strlen("drawFigure ")) == 0 ) {
            Lines[currentLine].commandType = DRAWFIGURE;
        }
        else if ( strncmp( Lines[currentLine].lineString, "printFigure ",
                    strlen("printFigure ")) == 0 ) {
            Lines[currentLine].commandType = PRINTFIGURE;
        }
        else if ( strncmp( Lines[currentLine].lineString, "translate ",
                    strlen("translate ")) == 0 ) {
            Lines[currentLine].commandType = TRANSLATE;
        }
        else if ( strncmp( Lines[currentLine].lineString, "child ",
                    strlen("child ")) == 0 ) {
            Lines[currentLine].commandType = CHILD;
        }
        else
            return 1;

        currentLine++;
    }

    return 0;
}

/* getFigureSpecs() takes a Line * Lines, and checks for a tag FIGURES
 * inside each line.  When a tag is found, properties about the figure
 * defined at that line are stored in Figure * Figures. */
void getFigureSpecs (Line * Lines, Figure * Figures ) {

    /* Local string buffers. */
    char tempbuf[6+1];
    char localFigName[MAXLEN_FIG+1];

    /* Holds an index for a
     * previously defined figure. */
    int figIndex;

    /* Local figure count; keeps track
     * defined figures vs MAXFIGS allowed. */
    int localFigCount = 0;

    int currentLine = 0;

    /* Look for up to permitted boundaries. */
    while ( localFigCount < MAXFIGS && currentLine < inputFileLength-2 ) {

        /* When a figure is found... */
        if ( Lines[currentLine].commandType == FIGURE ) {

            /* Store its name on a temp buffer. */
            sscanf(Lines[currentLine].lineString, " %s%s",
                    tempbuf, localFigName);


            /* Check if a figure was previously defined. */
            if ( !(exists(localFigName, Figures)) ) {

                /* Store Figure name. */
                strncpy(Figures[localFigCount].figureName,
                        localFigName, MAXLEN_FIG+1);

                /* Initialize it and make it defined. */
                Figures[localFigCount].drawCount = 0;
                Figures[localFigCount].isdefined = 1;

                /* Update its (x, y) values. */
                update( Lines[currentLine].lineString,
                        Figures, localFigCount, 2);

                /* Look for draw commands if any. */
                currentLine++;

                while ( Figures[localFigCount].drawCount < MAX_SEGMENTS &&
                        Lines[currentLine].commandType != END &&
                        currentLine < inputFileLength ) {

                    if ( Lines[currentLine].commandType == DRAW )

                        /* Updates its (dx, dy) values
                         * and draw commands count. */
                        update( Lines[currentLine].lineString,
                                Figures, localFigCount, 1);

                    currentLine++;
                }

                /* Keep track of figures defined and stored. */
                localFigCount++;
            }

            else if ( exists(localFigName, Figures) ) {

                /* Get index of a previously defined figure. */
                figIndex = getindex(localFigName, Figures);

                /* Update its information. */
                update(Lines[currentLine].lineString, Figures, figIndex, 2);
                clear(Figures, figIndex, 0);

                currentLine++;

                /* And look for more draw commands (if not at limit). */
                while ( Figures[figIndex].drawCount < MAX_SEGMENTS &&
                        Lines[currentLine].commandType != END &&
                        currentLine < inputFileLength ) {

                    if ( Lines[currentLine].commandType == DRAW )

                        /* Update (dx, dy) values and draw commands count. */
                        update( Lines[currentLine].lineString,
                                Figures, figIndex, 1);

                    currentLine++;
                }
            }
        }
        else
            currentLine++;
    }
}

/* executeCommands() goes through each line in Lines, and checks for valid
 * Sketchpad commands.  When successful, it identifies the pertinent Figure
 * and calls drawPrintFigure() or translateFigure() depending on the tag.
 * A FILE * outputFile is required for drawPrintFigure() calls. */
void executeCommands ( FILE * outputFile, Line * Lines, Figure * Figures ) {

    char tempbuf[11+1];
    char figureName[MAXLEN_FIG+1];

    int type;
    int localFigCount = 0;
    int currentLine = 0;

    double tx, ty;      /* Deltas (x, y). */

    /* Execute translate, drawFigure, printFigure or child commands. */
    for (currentLine = 0; currentLine < inputFileLength; currentLine++) {

        switch( Lines[currentLine].commandType ) {

            case DRAWFIGURE:        /* This cases share same syntax, */
            case PRINTFIGURE:       /* so grou them together and get */
            case TRANSLATE:         /* the parameters.               */

                type = Lines[currentLine].commandType;

                sscanf( Lines[currentLine].lineString, " %s%s%lf%lf",
                        tempbuf, figureName, &tx, &ty);

                /* Looks for at most MAXFIGS previously stored. */
                for ( localFigCount = 0;
                      localFigCount < MAXFIGS; localFigCount++ ) {

                    /* When appropriate figure is found... */
                    if ( strncmp(Figures[localFigCount].figureName, figureName,
                                (strlen(figureName)+1) ) == 0 ) {

                        /* Call the appropriate functions. */
                        if ( type == DRAWFIGURE || type == PRINTFIGURE )
                            drawPrintFigure(outputFile, Figures,
                                            localFigCount, type);
                        else
                            translateFigure(Figures, localFigCount, tx, ty);

                        break;
                    }
                }
                break;  /* Switch break. */


            case CHILD:
                sendChildCommands(outputFile, Lines, currentLine);
                break;


            case COMMENT:       /* See note at line 61. */
                if ( (inputFileLength - currentLine) == 2 )
                    printf("%s\n", Lines[currentLine].lineString);

            default:
                break;
        }
    }
}

/* drawPrintFigure() takes a Figure * Figures the definition stored
 * in index.  Commands are piped to outputFile or printed to stdout
 * depending on type. */
void drawPrintFigure( FILE * outputFile, Figure * Figures,
                      int figureCount, int type) {

    int drawCount;
    long x, y;          /* Current (x, y) pen position. */
    long dx, dy;        /* Deltas (x, y) for current pen position. */
    long xNew, yNew;    /* New (x, y) pen position after deltas are applied. */

    /* Retrieve data. */
    drawCount = Figures[figureCount].drawCount;
    x = lround( Figures[figureCount].x );
    y = lround( Figures[figureCount].y );

    /* Carry out appropiate actions depending on command type. */
    if (type == PRINTFIGURE) {
        printf("Print Figure %s =\n", Figures[figureCount].figureName);
        printf("%ld %ld\n", x, y);
    }

    int i;  /* Repeat up to the amount of draw commands found. */
    for (i = 0; i < drawCount; i++) {

        /* Retrieve deltas (x, y). */
        dx = lround( Figures[figureCount].dx[i] );
        dy = lround( Figures[figureCount].dy[i] );
        xNew = x + dx;
        yNew = y + dy;

        /* Carry out appropriate action according to specification. */
        if (type == PRINTFIGURE)
            printf("%ld %ld\n", xNew, yNew);
        else
            fprintf(outputFile, "drawSegment %ld %ld %ld %ld\n",
                    x, y, xNew, yNew);

        x = xNew;
        y = yNew;
    }

    if (type == PRINTFIGURE)
        printf("End Figure %s\n", Figures[figureCount].figureName);
}

/* translateFigure() transforms Figure * Figures at index by adding the
 * deltas (tx, ty) to the current stored (x, y) values. */
void translateFigure ( Figure * Figures, int figureCount,
                       double tx, double ty) {

    /* Add (tx, ty) to current (x, y). */
    Figures[figureCount].x += tx;
    Figures[figureCount].y += ty;
}

/* sendChildCommands() pipes to outputFile commands following the "child"
 * keyword up to the end of the string found in Line * Lines at lineNumber. */
void sendChildCommands (FILE * outputFile, Line * Lines, int currentLine) {

    char * childCommands;

    int strLength = strlen(Lines[currentLine].lineString);

    /* Get substring of commands which should follow child. */
    childCommands = substr(Lines[currentLine].lineString, 5, strLength-5);

    /* Send substring of commands to Sketchpad.jar. */
    fprintf(outputFile, "%s\n", childCommands);

    free(childCommands);

}
